package com.itclass.auth.authentication.provider.support;

import com.alibaba.fastjson2.JSON;
import com.itclass.auth.authentication.provider.AbstractUserDetailsAuthenticationProvider;
import com.itclass.auth.authentication.token.supprt.GitHubLoginAuthenticationToken;


import com.itclass.auth.context.AuthServerApplicationContext;
import com.itclass.auth.exception.GitHubAuthenticationServiceException;
import com.itclass.auth.pojo.db.SysUser;
import com.itclass.auth.pojo.dto.AuthUserDetails;
import com.itclass.auth.pojo.dto.GithubUser;
import com.itclass.auth.pojo.dto.UserDetailsDTO;
import com.itclass.auth.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;

@Component
@Slf4j
public class GitHubAuthAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider<GitHubLoginAuthenticationToken> {
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private RestTemplate request;
    @Autowired
    private AuthServerApplicationContext serverApplicationContext;

    @Override
    public boolean supports(Class<?> authentication) {
        return GitHubLoginAuthenticationToken.class.isAssignableFrom(authentication);
    }


    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, GitHubLoginAuthenticationToken authentication) throws AuthenticationException {

    }

    @Override
    protected void check(Authentication authentication) {
        Assert.isInstanceOf(GitHubLoginAuthenticationToken.class, authentication, () -> {
            return this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports", "Only UsernamePasswordLoginAuthenticationToken is supported");
        });
    }

    @Override
    protected UserDetails retrieveUser(String code, Authentication authentication) throws AuthenticationException {
        try {
            String accessTokenUrl = getAccessTokenUrl(code);

            String data = request.postForObject(accessTokenUrl, String.class, String.class);

            String[] str = data.split("&");
            String access_token = str[0].substring(str[0].indexOf("=") + 1);
            HttpHeaders headers = new HttpHeaders();
            headers.set("Authorization", "token " + access_token);
            HttpEntity<String> entity = new HttpEntity<>(headers);
            ResponseEntity<String> response = request.exchange(serverApplicationContext.getUserInfoUrl(), HttpMethod.GET, entity, String.class);
            HttpStatus statusCode = response.getStatusCode();
            if (200 != statusCode.value()) {
                throw new GitHubAuthenticationServiceException("github 登录认证失败");
            }
            GithubUser githubUser = JSON.parseObject(response.getBody(), GithubUser.class);
            SysUser sysUser = sysUserService.saveGithubUser(githubUser);
            if (sysUser == null) {
                throw new GitHubAuthenticationServiceException("github 登录认证失败");
            }
            return AuthUserDetails.buildUserDetail(sysUser);
        } catch (Exception e) {
            log.error("github 登录认证失败",e);
            throw new GitHubAuthenticationServiceException(e.getMessage());
        }
    }

    private String getAccessTokenUrl(String code) {
        StringBuilder sb = new StringBuilder();
        sb.append(serverApplicationContext.getAccessTokenUrl());
        sb.append("?client_id=");
        sb.append(serverApplicationContext.getClientId());
        sb.append("&code=");
        sb.append(code);
        sb.append("&redirect_uri=");
        sb.append(serverApplicationContext.getRedirectUri());
        sb.append("&client_secret=");
        sb.append(serverApplicationContext.getClientSecret());

        return sb.toString();
    }
    protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {

        GitHubLoginAuthenticationToken result = new GitHubLoginAuthenticationToken();

        AuthUserDetails userDetails = (AuthUserDetails) user;
        result.setPrincipal(user.getUsername());
        UserDetailsDTO userDetailsDTO = UserDetailsDTO.buildUserDetail(userDetails);
        result.setDetails(userDetailsDTO);

        result.setAuthorities(userDetails.getRoles());
        return result;
    }
}
